package ai;

import model.ChessAction;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * 单例模式构造困难模式AI
 *
 * @author 任禹名
 */
public class HardAI implements Ai {
    private static HardAI instance;

    private HardAI(ChessAction chessAction) {
        this.chessAction = chessAction;
        this.nowTable = chessAction.getNowTable();
    }

    public static HardAI getInstance(ChessAction chessAction) {
        if (instance == null)
            instance = new HardAI(chessAction);
        return instance;
    }

    private final int BLACK = 1, WHITE = 2;
    private ChessNode[][] nowHardTable = new ChessNode[15][15];
    private ChessNode ansNode;
    private ChessAction chessAction;
    private int level = 3;//博弈树深度
    private int node = 10;//每个节点的子节点数量
    private int[][] nowTable;
    private Values values = Values.getInstance();

    @Override
    public void delete(int x, int y) {
        nowHardTable[x][y] = null;
    }

    @Override
    public void reset(ChessAction chessAction) {
        this.chessAction = chessAction;
        this.nowTable = chessAction.getNowTable();
        for (int i = 0; i < 15; i++) {
            for (int j = 0; j < 15; j++) {
                nowHardTable[i][j] = null;
            }
        }
    }

    @Override
    public int[] downChess(int chessColor) {
        for (int i = 0; i < 15; i++) {
            for (int j = 0; j < 15; j++) {
                nowHardTable[i][j] = new ChessNode(i, j, 0);
                nowHardTable[i][j].setPlayer(nowTable[i][j]);
            }
        }
        int[] result = new int[2];//用来保存结果
        ChessNode chessNode;
        getValueByTree(0, chessColor, nowHardTable, -Integer.MAX_VALUE,
                Integer.MAX_VALUE);
        chessNode = ansNode;
        result[0] = chessNode.getX();
        result[1] = chessNode.getY();
        return result;
    }

    /**
     * 递归，根据博弈树获取ansNode.
     *
     * @param depth            当前博弈层深度
     * @param player
     * @param hardTableForTree 真实棋盘
     * @param alpha
     * @param beta
     * @return 当前层的得分.
     */
    public int getValueByTree(int depth, int player, ChessNode[][] hardTableForTree, int alpha, int beta) { //
        ChessNode[][] hardTableClone = clone(hardTableForTree);    //复制一份棋盘用于模拟
        List<ChessNode> orderList = getSortList(player, hardTableClone);    //根据空位权值对每个空位排序
        if (depth == level) {
            // 如果达到了目标搜索深度，返回当前局势得分
            return orderList.get(0).getSum();
        }

        for (int i = 0; i < node; i++) {//启发式搜索,选择得分前node个节点
            ChessNode chessNode = orderList.get(0);
            int score;
            if (chessNode.getSum() > 10000) {//values.Level.ALIVE_4.score
                //找到杀棋
                score = chessNode.getSum();
            } else {
                // 模拟下棋
                hardTableClone[chessNode.getX()][chessNode.getY()] = chessNode;
                hardTableClone[chessNode.getX()][chessNode.getY()].setPlayer(player);
                score = getValueByTree(depth + 1, 3 - player, hardTableClone, alpha, beta);
            }
            //博弈部分
            if (depth % 2 == 0) {
                // AI层
                if (score > alpha) {
                    alpha = score;
                    if (depth == 0) {
                        ansNode = chessNode;
                    }
                }
                if (alpha >= beta) {
                    //剪枝
                    score = alpha;
                    return score;
                }
            } else {
                //对手层
                if (score < beta) {
                    beta = score;
                }
                if (alpha >= beta) {
                    // 剪枝
                    score = beta;
                    return score;
                }
            }
        }
        return depth % 2 == 0 ? alpha : beta;//AI层返回最大，对手层返回最小
    }

    /**
     * 浅拷贝棋局.
     *
     * @param hardTable
     * @return
     */
    private ChessNode[][] clone(ChessNode[][] hardTable) //复制棋局
    {
        ChessNode[][] hardTableClone = new ChessNode[15][15];
        for (int i = 0; i < 15; i++) {
            for (int j = 0; j < 15; j++) {
                if (hardTable[i][j] != null) {
                    hardTableClone[i][j] = new ChessNode(hardTable[i][j].getX(), hardTable[i][j].getY(),
                            hardTable[i][j].getPlayer());
                } else {
                    hardTableClone[i][j] = null;
                }

            }
        }

        return hardTableClone;
    }


    /**
     * 根据权值对所有点排序.
     *
     * @param player
     * @param hardTable
     * @return 排序后的棋子List
     */
    private List<ChessNode> getSortList(int player, ChessNode[][] hardTable) {
        List<ChessNode> list = new ArrayList<>();
        for (int i = 0; i < 15; i++) {
            for (int j = 0; j < 15; j++) {
                if (hardTable[i][j].getPlayer() == 0) {
                    ChessNode chessNode = hardTable[i][j];
                    // 攻击分
                    int offense = values.getValue(i, j, player, hardTable);
                    // 防守分
                    int defence = values.getValue(i, j, 3 - player, hardTable);
                    chessNode.setOffense(offense);
                    chessNode.setDefence(defence);
                    chessNode.setSum(offense + defence);
                    list.add(chessNode);
                }
            }
        }
        Collections.sort(list); // 排序
        return list;
    }
}
